package server.main;

import common.EnvelopeMessage;
import server.dispatcher.Dispatcher;
import server.handler.friendHandler.*;
import server.handler.groupHandler.*;
import server.handler.userHandler.*;
import server.session.ClientContext;
import server.session.Session;
import server.session.SessionChecker;
import server.session.SessionManager;

import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.nio.charset.StandardCharsets;
import java.util.Iterator;

public class MainServer {
    public static void main(String[] args) throws Exception {
        //多路复用器
        Selector selector = Selector.open();
        ServerSocketChannel ssc = ServerSocketChannel.open();
        ssc.configureBlocking(false);//设置非阻塞

        ssc.bind(new InetSocketAddress( 8080));
        ssc.register(selector, SelectionKey.OP_ACCEPT);//绑定端口和事件

        SessionChecker.start();//心跳检测器

        Dispatcher dispatcher = new Dispatcher();
        dispatcher.register("user", "login", new LoginHandler());
        dispatcher.register("user", "register", new RegisterHandler());
        dispatcher.register("chat", "private", new PrivateChatHandler());
        dispatcher.register("chat", "group", new GroupChatHandler());
        dispatcher.register("history", "group", new GroupHistoryHandler());
        dispatcher.register("history", "private", new PrivateHistoryHandler());
        dispatcher.register("friend", "list", new FriendListHandler());
        dispatcher.register("group", "list", new GroupListHandler());
        dispatcher.register("group", "create", new GroupCreateHandler());
        dispatcher.register("friend", "search", new FriendSearchHandler());
        dispatcher.register("friend", "request", new FriendRequestHandler());
        dispatcher.register("friend", "requestCancel", new FriendRequestCancelHandler());
        dispatcher.register("friend", "delete", new FriendDeleteHandler());
        dispatcher.register("friend", "block", new FriendBlockHandler());
        dispatcher.register("friend", "blockCancel", new FriendBlockCancelHandler());
        dispatcher.register("notification", "list", new NotificationListHandler());
        dispatcher.register("friend", "response", new FriendResponseHandler());
        dispatcher.register("group", "search", new GroupSearchHandler());
        dispatcher.register("group", "request", new GroupRequestHandler());
        dispatcher.register("group", "requestCancel", new GroupRequestCancelHandler());
        dispatcher.register("group", "response", new GroupResponseHandler());
        dispatcher.register("group", "invite", new GroupInviteHandler());
        dispatcher.register("group", "kick", new GroupKickHandler());
        dispatcher.register("group", "disband", new GroupDisbandHandler());
        dispatcher.register("group", "quit", new GroupQuitHandler());
        dispatcher.register("group","mute",new GroupMuteHandler());
        dispatcher.register("group","mutedList",new GroupMutedListHandler());
        dispatcher.register("heart", "beat", new HeartBeatHandler());
        dispatcher.register("user", "logout", new UserLogoutHandler());
        while (true) {
            selector.select();
            Iterator<SelectionKey> itr = selector.selectedKeys().iterator();
            while (itr.hasNext()) {
                SelectionKey key = itr.next();
                itr.remove();  // 处理前移除，防止重复处理

                if (key.isAcceptable()) {  // 处理新连接事件
                    // 获取服务器通道并接受客户端连接
                    ServerSocketChannel serverChannel = (ServerSocketChannel) key.channel();
                    SocketChannel clientChannel = serverChannel.accept();
                    clientChannel.configureBlocking(false);  // 设置为非阻塞模式

                    // 为每个连接创建独立的Buffer和Session对象，方便后期复用
                    ByteBuffer buffer = ByteBuffer.allocate(1024 * 1024);  // 分配1MB缓冲区
                    Session session = new Session(clientChannel);  // 创建会话对象

                    // 使用ClientContext封装这个会话和缓冲区
                    ClientContext ctx = new ClientContext(buffer, session, new StringBuilder());

                    // 注册读事件，并将ClientContext附加到key上
                    clientChannel.register(selector, SelectionKey.OP_READ, ctx);

                    System.out.println("新客户端连接: " + clientChannel.getRemoteAddress());

                } else if (key.isReadable()) {  // 处理读事件
                    // 获取通道和缓冲区
                    SocketChannel client = (SocketChannel) key.channel();
                    ClientContext ctx = (ClientContext) key.attachment();  //  获取绑定的ClientContext
                    ByteBuffer buffer = ctx.buffer;
                    Session session = ctx.session;  //  复用已存在的Session对象

                    // 读取数据到缓冲区
                    int read = client.read(buffer);
                    if (read == -1) {  // 连接已关闭
                        System.out.println("客户端断开连接: " + client.getRemoteAddress());

                        // 清理会话资源
                        if (session.getClientId() != null) {
                            SessionManager.remove(session.getClientId());
                        }

                        key.cancel();  // 取消监听
                        client.close();  // 关闭通道
                        continue;
                    }

                    // 处理接收到的数据
                    buffer.flip();  // 切换为读模式
                    String received = StandardCharsets.UTF_8.decode(buffer).toString();
                    buffer.clear();

                    // 把新收到的数据追加到缓存
                    ctx.partialMessage.append(received);

                    // 处理所有完整消息
                    String allData = ctx.partialMessage.toString();
                    int index;
                    while ((index = allData.indexOf("\n")) >= 0) {
                        String json = allData.substring(0, index).trim();
                        allData = allData.substring(index + 1);

                        if (!json.isEmpty()) {
                            try {
                                EnvelopeMessage msg = EnvelopeMessage.fromJson(json);
                                dispatcher.dispatch(msg, session);
                                System.out.println("处理消息: " + json);
                            } catch (Exception e) {
                                System.err.println("消息处理异常: " + e.getMessage());
                            }
                        }
                    }

                    // 保存半截消息
                    ctx.partialMessage.setLength(0);
                    ctx.partialMessage.append(allData);

                }
            }
        }

    }
    // I believe you , you can finish it.
}
